package server;
import common.*;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

/**
 * Classe che si occupa di accettare le richieste di connessione da parte dei client che si collegano tramite protocollo socket. Una volta presa la connessione, fa partire il thread associato a quella connessione, permettendo di rimanere sempre in ascolto su quel socket.
 */
public class Server_socket extends Thread implements Server{

	private Gioco gioco;
	private Partita partita;
	private ArrayList<Socket> listaconnessioni;
	private ArrayList<Server_listener> listathread;
	private ServerSocket ss;
	private Socket sock;
	
	/**
	 * Costruttore di classe, istanzia i riferimenti agli oggetti che servono a gestire la partita.
	 * @param gioco Oggetto Gioco.
	 * @param partita Oggetto Partita.
	 */
	public Server_socket(Gioco gioco, Partita partita){
		
		this.gioco = gioco;
		this.partita = partita;
		listaconnessioni = new ArrayList<Socket>();
		listathread = new ArrayList<Server_listener>();
		try {
			ss = new ServerSocket(34567);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Metodo che permette di far partire il thread che si occupa di mantenere attiva la classe. Fa partire l'ascolto sulla porta di default.
	 */
	public void run(){
		try {
			listening();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Metodo che fa restare il thread in ascolto in attesa di richieste di connessioni. Quando una connessione viene accettata, viene istanziato e fatto partire il thread che si occupera' di restare in ascolto sul socket. Il thread e il rispettivo socket vengono quindi memorizzati in un arraylist.
	 * @throws IOException Eccezione lanciata in caso di errori di Input/Output.
	 */
	private void listening() throws IOException{
		
		while(true){
			System.out.println("Server in ascolto dal thread: " + Thread.currentThread());
			sock = ss.accept();
			System.out.println("Ricevuta connessione su: " + sock.getInetAddress() + "su porta: " + sock.getPort());
			listaconnessioni.add(sock);
			Server_listener ch = new Server_listener(gioco, partita, sock, this);
			listathread.add(ch);
			ch.start();
		}
	}
	
	/**
	 * Metodo che si occupa di eliminare dalla lista delle connessioni e dei thread gli oggetti inerenti al socket per cui si sta chiudendo la connessione.
	 * @param sock Socket da chiudere.
	 * @param th Thread di cui si deve interrompere l'esecuzione.
	 */
	public synchronized void closeConnection(Socket sock, Thread th){
		
		listaconnessioni.remove(sock);
		listathread.remove(th);
		System.out.println("thread " + th + " interrotto, " + Thread.currentThread());
	}
	
	@Override
	public void cambioTurno(String username){
		
		for(int i = 0; i < listathread.size(); i++){
			listathread.get(i).cambioTurno(username);
		}
	}
	
	@Override
	public void specieMorta(String username, Boolean bul){
		
		for(int i = 0; i < listathread.size(); i++){
			listathread.get(i).specieMorta(username);
		}
	}
}
